D) Virtual Function

Virutaul Function
가상 함수는 기본 클래스(상속되지 않은 클래스) 내에서 선언되어 파생 클래스에 의해 재정의 되는 멤버 함수이다.

포인터(Pointer) 또는 기본 클래스에 대한 참조(Reference)를 사용하여
파생 클래스의 객체를 참조하면 해당 객체에 대해 가상함수를 호출하고, 파생 클래스의 함수를 실행할 수 있다.

주로 실행시간(Runtime)에 함수의 다형성(Polymorphism)을 구현하는데 사용
가상 함수 선언 규칙
1. 클래스의 공개(public) 세션에 선언한다.
2. 가상 함수는 정적(static)일 수 없으며, 다른 클래스의 친구(friend) 함수가 될 수 없다.
3. 가상 함수는 실행시간 다형성을 얻기 위해, 기본 클래스의 포인터 또는 참조를 통해 접근해야 한다.
4. 가상 함수의 프로토타입(반환형과 매개변수)은 기본 클래스와 파생 클래스에서 동일하다.
5. 클래스는 가상 소멸자를 가질 수 있지만, 가상 생성자를 가질 수 없다.
#include <iostream>
using namespace std;
class parent{
public:
virtual void v_print(void){
cout<<"parent"<<"\n";
}
void print(void){
cout<<"parent"<<"\n";
}
};
class child: public parent{
public:
void v_print(void){
cout<<"child"<<"\n";
}
void print(void){
cout<<"child"<<"\n";
}
};
int main(void){
parent* p;
child c;
p=&c;
p->v_print();
p->print();
return 0;
}

child

parent

virtual로 선언된 v_print 함수는 가상함수이다.
가상 함수는 실행시간(런타임)에 그 값이 결정된다.(지연 바인딩)

p->print() 일반함수는 컴파일 타임에 parent 클래스의 print() 함수가 호출된다고 결정된다.
p->v_print() 가상함수는 런타임에 child 클래스의 v_print() 수가 사용된다고 결정된다.
#include <iostream>
using namespace std;
class parent{
public:
void print1(void){
cout<<"parent print1"<<"\n";
}
virtual void print2(void){
cout<<"parent print2"<<"\n";
}
virtual void print3(void){
cout<<"parent print3"<<"\n";
}
};
class child: public parent{
public:
void print2(void){
cout<<"child print2"<<"\n";
}
void print3(int x){
cout<<"child print3"<<"\n";
}
};
int main(void){
parent* p;
child c;
p=&c;
p->print1();
p->print2();
p->print3();
return 0;
}

parent print1

child print2

parent print3

print1()은 일반함수로 선언되었으며,
print2(), print3()은 virtual 키워드를 통해 가상함수로 선언되었다.
또한 상속받은 child 클래스에서 print3()함수를 오버라이딩하여 매개변수를 추가하였다.

print1()은 일반함수이기 때문에 컨파일 타임에 parent 클래스에서 호출된다고 결정된다.
print2()은 가상함수이기 때문에 실행 시간에 결정된다. p는 parent 객체를 가리키는 포인터이지만,
객체가 child클래스 이기 때문에 child 클래스의 print2() 함수가 호출된다.
print3()는 가상함수이지만, child 클래스에서 매개변수가 없는 함수를 호출했기 때문에 부모 클래스인
parent 클래스의 parent 클래스의 함수가 호출된다.